From 68ed97c9f5dd6240db835d6840805f33040b3c27 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 27 Oct 2006 07:45:10 +0000 Subject: [PATCH] add diag rewrite SVN-Revision: 5309 --- .../base-files/default/etc/functions.sh | 27 + .../base-files/default/etc/init.d/S99done | 4 +- .../package/base-files/default/etc/preinit | 28 +- .../base-files/default/sbin/hotplug.failsafe | 3 + .../target/linux/package/diag/src/Makefile | 23 +- openwrt/target/linux/package/diag/src/diag.c | 835 ++++++++++++++++++ .../target/linux/package/diag/src/diag_led.c | 340 ------- 7 files changed, 898 insertions(+), 362 deletions(-) create mode 100755 openwrt/package/base-files/default/sbin/hotplug.failsafe create mode 100644 openwrt/target/linux/package/diag/src/diag.c delete mode 100644 openwrt/target/linux/package/diag/src/diag_led.c diff --git a/openwrt/package/base-files/default/etc/functions.sh b/openwrt/package/base-files/default/etc/functions.sh index 9fecccf7d4..b33338b216 100755 --- a/openwrt/package/base-files/default/etc/functions.sh +++ b/openwrt/package/base-files/default/etc/functions.sh @@ -169,3 +169,30 @@ include() { . $file done } + +set_led() { + local led="$1" + local state="$2" + [ -f "/proc/diag/led/$1" ] && echo "$state" > "/proc/diag/led/$1" +} + +set_state() { + case "$1" in + preinit) + set_led dmz 1 + set_led diag 1 + set_led power 0 + ;; + failsafe) + set_led diag 0 && led=diag + set_led power 1 && led=power + set_led dmz 0 && led=dmz + while :; do { set_led "$led" $(((X=(X+1)%8)%2)); sleep $((X==0)); } done & + ;; + done) + set_led dmz 0 + set_led diag 0 + set_led power 1 + ;; + esac +} diff --git a/openwrt/package/base-files/default/etc/init.d/S99done b/openwrt/package/base-files/default/etc/init.d/S99done index 9682c0c85f..e28cb7aec7 100755 --- a/openwrt/package/base-files/default/etc/init.d/S99done +++ b/openwrt/package/base-files/default/etc/init.d/S99done @@ -1,4 +1,6 @@ #!/bin/sh +. /etc/functions.sh + sysctl -p >&- # automagically run firstboot @@ -11,4 +13,4 @@ sysctl -p >&- } # set leds to normal state -echo "0x02" > /proc/sys/diag +set_state done diff --git a/openwrt/package/base-files/default/etc/preinit b/openwrt/package/base-files/default/etc/preinit index a663c1a955..499bf74f90 100755 --- a/openwrt/package/base-files/default/etc/preinit +++ b/openwrt/package/base-files/default/etc/preinit @@ -1,9 +1,10 @@ #!/bin/sh +. /etc/functions.sh export PATH=/bin:/sbin:/usr/bin:/usr/sbin mount none /proc -t proc insmod diag -echo 0x01 > /proc/sys/diag +set_state preinit ifname=eth0 # WAP54G, WL-HDD @@ -32,18 +33,8 @@ ifconfig $ifname 192.168.1.1 netmask 255.255.255.0 broadcast 192.168.1.255 up netmsg 192.168.1.0 "(dummy message)" # b44 eats the first packet netmsg 192.168.1.255 "Press reset now, to enter Failsafe!" -sleep 2 - -if [ "$(cat /proc/sys/reset 2>&-)" = 1 -o "$(nvram get failsafe)" = 1 ]; then - while :; do { echo $((((X=(X+1)%8)%2)*3)) > /proc/sys/diag; sleep $((X==0)); } done & - export FAILSAFE=true - [ "$(nvram get boot_wait)" != "on" ] && { - nvram set boot_wait=on - nvram commit - } - netmsg 192.168.1.255 "Entering Failsafe!" - telnetd -l /bin/login <> /dev/null 2>&1 -else +echo /sbin/hotplug.failsafe > /proc/sys/kernel/hotplug +if sleep 2; then ifconfig $ifname 0.0.0.0 # revert to the boot loader's vlan config @@ -53,7 +44,18 @@ else echo "$v1p" > /proc/switch/eth0/vlan/1/ports echo "$v2p" > /proc/switch/eth0/vlan/2/ports } +else + # sleep was interrupted by a hotplug event - enter failsafe mode + set_state failsafe + export FAILSAFE=true + [ "$(nvram get boot_wait)" != "on" ] && { + nvram set boot_wait=on + nvram commit + } + netmsg 192.168.1.255 "Entering Failsafe!" + telnetd -l /bin/login <> /dev/null 2>&1 fi +echo /sbin/hotplug > /proc/sys/kernel/hotplug insmod mini_fo 2>&- mount_root ${FAILSAFE:+failsafe} diff --git a/openwrt/package/base-files/default/sbin/hotplug.failsafe b/openwrt/package/base-files/default/sbin/hotplug.failsafe new file mode 100755 index 0000000000..f2091e0a48 --- /dev/null +++ b/openwrt/package/base-files/default/sbin/hotplug.failsafe @@ -0,0 +1,3 @@ +#!/bin/sh +# trigger for failsafe mode +[ "$1" = "button" ] && killall sleep diff --git a/openwrt/target/linux/package/diag/src/Makefile b/openwrt/target/linux/package/diag/src/Makefile index 25781908d7..deb97efd40 100644 --- a/openwrt/target/linux/package/diag/src/Makefile +++ b/openwrt/target/linux/package/diag/src/Makefile @@ -1,13 +1,20 @@ -#$Id: 005-diag_led.patch 4594 2006-08-18 13:10:19Z florian $ +# $Id$ +# +# Makefile for the diag driver +# +# Copyright (C) 2006 Felix Fietkau +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version +# 2 of the License, or (at your option) any later version. +# EXTRA_CFLAGS := -I$(TOPDIR)/arch/mips/bcm947xx/include -DBCMDRIVER -O_TARGET := diag.o +obj-m := diag.o -MAC_OBJS := diag_led.o +ifeq ($(MAKING_MODULES),1) +-include $(TOPDIR)/Rules.make +endif -export-objs := -obj-y := $(MAC_OBJS) -obj-m := $(O_TARGET) - -include $(TOPDIR)/Rules.make diff --git a/openwrt/target/linux/package/diag/src/diag.c b/openwrt/target/linux/package/diag/src/diag.c new file mode 100644 index 0000000000..abd682ac45 --- /dev/null +++ b/openwrt/target/linux/package/diag/src/diag.c @@ -0,0 +1,835 @@ +/* + * diag.c - GPIO interface driver for Broadcom boards + * + * Copyright (C) 2006 Mike Baker , + * Felix Fietkau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define MODULE_NAME "diag" + +#undef AUTO +#define MAX_GPIO 8 + +//#define DEBUG +//#define BUTTON_READ + +static unsigned int gpiomask = 0; +module_param(gpiomask, int, 0644); + +enum polarity_t { + AUTO = 0, + NORMAL = 1, + REVERSE = 2, +}; + +enum { + PROC_BUTTON, + PROC_LED, + PROC_MODEL, + PROC_GPIOMASK +}; + +struct prochandler_t { + int type; + void *ptr; +}; + + +struct button_t { + struct prochandler_t proc; + char *name; + u16 gpio; + u8 polarity; + u8 pressed; + unsigned long seen; +}; + +struct led_t { + struct prochandler_t proc; + char *name; + u16 gpio; + u8 polarity; +}; + +struct platform_t { + char *name; + struct button_t buttons[MAX_GPIO]; + struct led_t leds[MAX_GPIO]; +}; + +enum { + /* Linksys */ + WAP54GV1, + WAP54GV3, + WRT54GV1, + WRT54G, + WRTSL54GS, + WRT54G3G, + + /* ASUS */ + WLHDD, + WL300G, + WL500G, + WL500GD, + WL500GP, + ASUS_4702, + + /* Buffalo */ + WBR2_G54, + WHR_G54S, + WHR_HP_G54, + WLA2_G54L, + BUFFALO_UNKNOWN, + BUFFALO_UNKNOWN_4710, + + /* Siemens */ + SE505V1, + SE505V2, + + /* US Robotics */ + USR5461, + + /* Dell */ + TM2300, + + /* Motorola */ + WR850GV1, + WR850GV2, +}; + +static struct platform_t platforms[] = { + /* Linksys */ + [WAP54GV1] = { + .name = "Linksys WAP54G V1", + .buttons = { + { .name = "reset", .gpio = 1 << 0 }, + }, + .leds = { + { .name = "diag", .gpio = 1 << 3 }, + { .name = "wlan", .gpio = 1 << 4 }, + }, + }, + [WAP54GV3] = { + .name = "Linksys WAP54G V3", + .buttons = { + /* FIXME: verify this */ + { .name = "reset", .gpio = 1 << 7 }, + { .name = "ses", .gpio = 1 << 0 }, + }, + .leds = { + /* FIXME: diag? */ + { .name = "ses", .gpio = 1 << 1 }, + }, + }, + [WRT54GV1] = { + .name = "Linksys WRT54G V1.x", + .buttons = { + { .name = "reset", .gpio = 1 << 6 }, + }, + .leds = { + /* FIXME */ + }, + }, + [WRT54G] = { + .name = "Linksys WRT54G(S)", + .buttons = { + { .name = "reset", .gpio = 1 << 6 }, + { .name = "ses", .gpio = 1 << 4 } + }, + .leds = { + { .name = "power", .gpio = 1 << 1, .polarity = NORMAL }, + { .name = "dmz", .gpio = 1 << 7 }, + { .name = "ses_white", .gpio = 1 << 2 }, + { .name = "ses_orange", .gpio = 1 << 3 }, + }, + }, + [WRTSL54GS] = { + .name = "Linksys WRTSL54GS", + .buttons = { + { .name = "reset", .gpio = 1 << 6 }, + { .name = "ses", .gpio = 1 << 4 } + }, + .leds = { + { .name = "power", .gpio = 1 << 1, .polarity = NORMAL }, + { .name = "dmz", .gpio = 1 << 7 }, + { .name = "ses_white", .gpio = 1 << 5 }, + { .name = "ses_orange", .gpio = 1 << 7 }, + }, + }, + [WRT54G3G] = { + .name = "Linksys WRT54G3G", + .buttons = { + { .name = "reset", .gpio = 1 << 6 }, + { .name = "3g", .gpio = 1 << 4 } + }, + .leds = { + { .name = "power", .gpio = 1 << 1, .polarity = NORMAL }, + { .name = "dmz", .gpio = 1 << 7 }, + { .name = "3g_green", .gpio = 1 << 2, .polarity = NORMAL }, + { .name = "3g_blue", .gpio = 1 << 3, .polarity = NORMAL }, + { .name = "3g_blink", .gpio = 1 << 5, .polarity = NORMAL }, + }, + }, + /* Asus */ + [WLHDD] = { + .name = "ASUS WL-HDD", + .buttons = { + { .name = "reset", .gpio = 1 << 6 }, + }, + .leds = { + { .name = "power", .gpio = 1 << 0 }, + }, + }, + [WL300G] = { + .name = "ASUS WL-500g", + .buttons = { + { .name = "reset", .gpio = 1 << 6 }, + }, + .leds = { + { .name = "power", .gpio = 1 << 0 }, + }, + }, + [WL500G] = { + .name = "ASUS WL-500g", + .buttons = { + { .name = "reset", .gpio = 1 << 6 }, + }, + .leds = { + { .name = "power", .gpio = 1 << 0 }, + }, + }, + [WL500GD] = { + .name = "ASUS WL-500g Deluxe", + .buttons = { + { .name = "reset", .gpio = 1 << 6 }, + }, + .leds = { + { .name = "power", .gpio = 1 << 0 }, + }, + }, + [WL500GP] = { + .name = "ASUS WL-500g Premium", + .buttons = { + { .name = "reset", .gpio = 1 << 0 }, + }, + .leds = { + { .name = "power", .gpio = 1 << 1, .polarity = NORMAL }, + { .name = "ses", .gpio = 1 << 4 }, + }, + }, + [ASUS_4702] = { + .name = "ASUS (unknown, BCM4702)", + .buttons = { + { .name = "reset", .gpio = 1 << 6 }, + }, + .leds = { + { .name = "power", .gpio = 1 << 0 }, + }, + }, + /* Buffalo */ + [WHR_G54S] = { + .name = "Buffalo WHR-G54S", + .buttons = { + { .name = "reset", .gpio = 1 << 4 }, + { .name = "ses", .gpio = 1 << 0 }, + }, + .leds = { + { .name = "diag", .gpio = 1 << 1 }, + { .name = "internal", .gpio = 1 << 3 }, + { .name = "ses", .gpio = 1 << 6 }, + }, + }, + [WBR2_G54] = { + .name = "Buffalo WBR2-G54", + /* FIXME: verify */ + .buttons = { + { .name = "reset", .gpio = 1 << 7 }, + }, + .leds = { + { .name = "diag", .gpio = 1 << 1 }, + }, + }, + [WHR_HP_G54] = { + .name = "Buffalo WHR-HP-G54", + /* FIXME: verify */ + .buttons = { + { .name = "reset", .gpio = 1 << 4 }, + { .name = "ses", .gpio = 1 << 0 }, + }, + .leds = { + { .name = "diag", .gpio = 1 << 1 }, + { .name = "internal", .gpio = 1 << 3 }, + { .name = "ses", .gpio = 1 << 6 }, + }, + }, + [WLA2_G54L] = { + .name = "Buffalo WLA2-G54L", + /* FIXME: verify */ + .buttons = { + { .name = "reset", .gpio = 1 << 7 }, + }, + .leds = { + { .name = "diag", .gpio = 1 << 1 }, + }, + }, + [BUFFALO_UNKNOWN] = { + .name = "Buffalo (unknown)", + .buttons = { + { .name = "reset", .gpio = 1 << 7 }, + }, + .leds = { + { .name = "diag", .gpio = 1 << 1 }, + }, + }, + [BUFFALO_UNKNOWN_4710] = { + .name = "Buffalo (unknown, BCM4710)", + .buttons = { + { .name = "reset", .gpio = 1 << 4 }, + }, + .leds = { + { .name = "diag", .gpio = 1 << 1 }, + }, + }, + /* Siemens */ + [SE505V1] = { + .name = "Siemens SE505 V1", + .buttons = { + /* No usable buttons */ + }, + .leds = { + { .name = "dmz", .gpio = 1 << 4 }, + { .name = "wlan", .gpio = 1 << 3 }, + }, + }, + [SE505V2] = { + .name = "Siemens SE505 V2", + .buttons = { + /* No usable buttons */ + }, + .leds = { + { .name = "power", .gpio = 1 << 5 }, + { .name = "dmz", .gpio = 1 << 0 }, + { .name = "wlan", .gpio = 1 << 3 }, + }, + }, + /* US Robotics */ + [USR5461] = { + .name = "U.S. Robotics USR5461", + .buttons = { + /* No usable buttons */ + }, + .leds = { + { .name = "wlan", .gpio = 1 << 0 }, + { .name = "printer", .gpio = 1 << 1 }, + }, + }, + /* Dell */ + [TM2300] = { + .name = "Dell TrueMobile 2300", + .buttons = { + { .name = "reset", .gpio = 1 << 0 }, + }, + .leds = { + { .name = "diag", .gpio = 1 << 7 }, + }, + }, + /* Motorola */ + [WR850GV1] = { + .name = "Motorola WR850G V1", + .buttons = { + { .name = "reset", .gpio = 1 << 0 }, + }, + .leds = { + { .name = "diag", .gpio = 1 << 3 }, + { .name = "wlan_red", .gpio = 1 << 5, .polarity = NORMAL }, + { .name = "wlan_green", .gpio = 1 << 7, .polarity = NORMAL }, + }, + }, + [WR850GV2] = { + .name = "Motorola WR850G V2", + .buttons = { + { .name = "reset", .gpio = 1 << 5 }, + }, + .leds = { + { .name = "diag", .gpio = 1 << 1 }, + { .name = "wlan", .gpio = 1 << 0 }, + { .name = "modem", .gpio = 1 << 7, .polarity = NORMAL }, + }, + }, +}; + +static struct proc_dir_entry *diag, *leds; + +extern void *bcm947xx_sbh; +#define sbh bcm947xx_sbh + +static int sb_irq(void *sbh); +static struct platform_t *platform; + +#include +static struct tq_struct tq; +extern char *nvram_get(char *str); + +static inline char *getvar(char *str) +{ + return nvram_get(str)?:""; +} + +static struct platform_t *platform_detect(void) +{ + char *boardnum, *boardtype, *buf; + + boardnum = getvar("boardnum"); + boardtype = getvar("boardtype"); + if (strncmp(getvar("pmon_ver"), "CFE", 3) == 0) { + /* CFE based - newer hardware */ + if (!strcmp(boardnum, "42")) { /* Linksys */ + if (!strcmp(boardtype, "0x0101")) + return &platforms[WRT54G3G]; + + if (!strcmp(getvar("et1phyaddr"),"5") && !strcmp(getvar("et1mdcport"), "1")) + return &platforms[WRTSL54GS]; + + /* default to WRT54G */ + return &platforms[WRT54G]; + } + + if (!strcmp(boardnum, "45")) { /* ASUS */ + if (!strcmp(boardtype,"0x042f")) + return &platforms[WL500GP]; + else + return &platforms[WL500GD]; + } + + if (!strcmp(boardnum, "10496")) + return &platforms[USR5461]; + } else { /* PMON based - old stuff */ + if (!strncmp(boardtype, "bcm94710dev", 11)) { + if (!strcmp(boardtype, "42")) + return &platforms[WRT54GV1]; + if (simple_strtoul(boardnum, NULL, 9) == 2) + return &platforms[WAP54GV1]; + } + if (!strncmp(getvar("hardware_version"), "WL500-", 6)) + return &platforms[WL500G]; + if (!strncmp(getvar("hardware_version"), "WL300-", 6)) { + /* Either WL-300g or WL-HDD, do more extensive checks */ + if ((simple_strtoul(getvar("et0phyaddr"), NULL, 0) == 0) && + (simple_strtoul(getvar("et1phyaddr"), NULL, 9) == 1)) + return &platforms[WLHDD]; + if ((simple_strtoul(getvar("et0phyaddr"), NULL, 0) == 0) && + (simple_strtoul(getvar("et1phyaddr"), NULL, 9) == 10)) + return &platforms[WL300G]; + } + + /* unknown asus stuff, probably bcm4702 */ + if (!strncmp(boardnum, "asusX", 5)) + return &platforms[ASUS_4702]; + + if ((simple_strtoul(getvar("GemtekPmonVer"), NULL, 0) == 9) && + (simple_strtoul(getvar("et0phyaddr"), NULL, 0) == 30)) + return &platforms[WR850GV1]; + } + + if ((buf = (nvram_get("melco_id") ?: nvram_get("buffalo_id")))) { + /* Buffalo hardware, check id for specific hardware matches */ + if (!strcmp(buf, "29bb0332")) + return &platforms[WBR2_G54]; + if (!strcmp(buf, "29129")) + return &platforms[WLA2_G54L]; + if (!strcmp(buf, "30189")) + return &platforms[WHR_HP_G54]; + if (!strcmp(buf, "30182")) + return &platforms[WHR_G54S]; + } + + if (buf || !strcmp(boardnum, "00")) {/* probably buffalo */ + if (!strncmp(boardtype, "bcm94710ap", 10)) + return &platforms[BUFFALO_UNKNOWN_4710]; + else + return &platforms[BUFFALO_UNKNOWN]; + } + + if (!strcmp(getvar("CFEver"), "MotoWRv203")) + return &platforms[WR850GV2]; + + /* not found */ + return NULL; +} + +static ssize_t diag_proc_read(struct file *file, char *buf, size_t count, loff_t *ppos); +static ssize_t diag_proc_write(struct file *file, const char *buf, size_t count, void *data); +static struct file_operations diag_proc_fops = { + read: diag_proc_read, + write: diag_proc_write +}; + + + +static ssize_t diag_proc_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ +#ifdef LINUX_2_4 + struct inode *inode = file->f_dentry->d_inode; + struct proc_dir_entry *dent = inode->u.generic_ip; +#else + struct proc_dir_entry *dent = PDE(file->f_dentry->d_inode); +#endif + char *page; + int len = 0; + + if ((page = kmalloc(1024, GFP_KERNEL)) == NULL) + return -ENOBUFS; + + if (dent->data != NULL) { + struct prochandler_t *handler = (struct prochandler_t *) dent->data; + switch (handler->type) { +#ifdef BUTTON_READ + case PROC_BUTTON: { + struct button_t * button = (struct button_t *) handler->ptr; + len = sprintf(page, "%d\n", button->pressed); + } +#endif + case PROC_LED: { + struct led_t * led = (struct led_t *) handler->ptr; + int in = (sb_gpioin(sbh) & led->gpio ? 1 : 0); + int p = (led->polarity == NORMAL ? 0 : 1); + len = sprintf(page, "%d\n", ((in ^ p) ? 1 : 0)); + break; + } + case PROC_MODEL: + len = sprintf(page, "%s\n", platform->name); + break; + case PROC_GPIOMASK: + len = sprintf(page, "%d\n", gpiomask); + break; + } + } + len += 1; + + if (*ppos < len) { + len = min_t(int, len - *ppos, count); + if (copy_to_user(buf, (page + *ppos), len)) { + kfree(page); + return -EFAULT; + } + *ppos += len; + } else { + len = 0; + } + + return len; +} + + +static ssize_t diag_proc_write(struct file *file, const char *buf, size_t count, void *data) +{ +#ifdef LINUX_2_4 + struct inode *inode = file->f_dentry->d_inode; + struct proc_dir_entry *dent = inode->u.generic_ip; +#else + struct proc_dir_entry *dent = PDE(file->f_dentry->d_inode); +#endif + char *page; + int ret = -EINVAL; + + if ((page = kmalloc(count + 1, GFP_KERNEL)) == NULL) + return -ENOBUFS; + + if (copy_from_user(page, buf, count)) { + kfree(page); + return -EINVAL; + } + page[count] = 0; + + if (dent->data != NULL) { + struct prochandler_t *handler = (struct prochandler_t *) dent->data; + switch (handler->type) { + case PROC_LED: { + struct led_t *led = (struct led_t *) handler->ptr; + int p = (led->polarity == NORMAL ? 0 : 1); + + if (led->gpio & gpiomask) + break; + sb_gpiocontrol(sbh, led->gpio, 0); + sb_gpioouten(sbh, led->gpio, led->gpio); + sb_gpioout(sbh, led->gpio, ((p ^ (page[0] == '1')) ? led->gpio : 0)); + break; + } + case PROC_GPIOMASK: + gpiomask = simple_strtoul(page, NULL, 16); + break; + } + ret = count; + } + + kfree(page); + return ret; +} + +static void hotplug_button(struct button_t *b) +{ + char *argv [3], *envp[6], *buf, *scratch; + int i; + + if (!hotplug_path[0]) + return; + + if (in_interrupt()) { + printk(MODULE_NAME ": HOTPLUG WHILE IN IRQ!\n"); + return; + } + + if (!(buf = kmalloc (256, GFP_KERNEL))) + return; + + scratch = buf; + + i = 0; + argv[i++] = hotplug_path; + argv[i++] = "button"; + argv[i] = 0; + + i = 0; + envp[i++] = "HOME=/"; + envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; + envp[i++] = scratch; + scratch += sprintf (scratch, "ACTION=%s", b->pressed?"pressed":"released") + 1; + envp[i++] = scratch; + scratch += sprintf (scratch, "BUTTON=%s", b->name) + 1; + envp[i++] = scratch; + scratch += sprintf (scratch, "SEEN=%ld", (jiffies - b->seen)/HZ) + 1; + envp[i] = 0; + + call_usermodehelper (argv [0], argv, envp); + kfree (buf); +} + +static void button_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + + struct button_t *b; + int in = sb_gpioin(sbh); + + for (b = platform->buttons; b->name; b++) { + if (b->gpio & gpiomask) + continue; + if (b->polarity != (in & b->gpio)) { + /* ASAP */ + b->polarity ^= b->gpio; + sb_gpiointpolarity(sbh, b->gpio, b->polarity); + + b->pressed ^= 1; +#ifdef DEBUG + printk(MODULE_NAME ": button: %s pressed: %d seen: %ld\n",b->name, b->pressed, (jiffies - b->seen)/HZ); +#endif + INIT_TQUEUE(&tq, (void *)(void *)hotplug_button, (void *)b); + schedule_task(&tq); + + b->seen = jiffies; + } + } +} + +static void register_buttons(struct button_t *b) +{ + int irq = sb_irq(sbh) + 2; + chipcregs_t *cc; + +#ifdef BUTTON_READ + struct proc_dir_entry *p; + + buttons = proc_mkdir("button", diag); + if (!buttons) + return; +#endif + + request_irq(irq, button_handler, SA_SHIRQ | SA_SAMPLE_RANDOM, "gpio", button_handler); + + for (; b->name; b++) { + if (b->gpio & gpiomask) + continue; + sb_gpioouten(sbh,b->gpio,0); + sb_gpiocontrol(sbh,b->gpio,0); + b->polarity = sb_gpioin(sbh) & b->gpio; + sb_gpiointpolarity(sbh, b->gpio, b->polarity); + sb_gpiointmask(sbh, b->gpio,b->gpio); +#ifdef BUTTON_READ + if ((p = create_proc_entry(b->name, S_IRUSR, buttons))) { + b->proc.type = PROC_BUTTON; + b->proc.ptr = (void *) b; + p->data = (void *) &b->proc; + p->proc_fops = &diag_proc_fops; + } +#endif + } + + if ((cc = sb_setcore(sbh, SB_CC, 0))) { + int intmask; + + intmask = readl(&cc->intmask); + intmask |= CI_GPIO; + writel(intmask, &cc->intmask); + } +} + +static void unregister_buttons(struct button_t *b) +{ + int irq = sb_irq(sbh) + 2; + + for (; b->name; b++) { + sb_gpiointmask(sbh, b->gpio, 0); +#ifdef BUTTON_READ + remove_proc_entry(b->name, buttons); +#endif + } +#ifdef BUTTON_READ + remove_proc_entry("buttons", diag); +#endif + + free_irq(irq, button_handler); +} + +static void register_leds(struct led_t *l) +{ + struct proc_dir_entry *p; + + leds = proc_mkdir("led", diag); + if (!leds) + return; + + for(; l->name; l++) { + sb_gpiointmask(sbh, l->gpio, 0); + if ((p = create_proc_entry(l->name, S_IRUSR, leds))) { + l->proc.type = PROC_LED; + l->proc.ptr = l; + p->data = (void *) &l->proc; + p->proc_fops = &diag_proc_fops; + } + } +} + +static void unregister_leds(struct led_t *l) +{ + for(; l->name; l++) { + remove_proc_entry(l->name, leds); + } + remove_proc_entry("led", diag); +} + +static void __exit diag_exit(void) +{ + if (platform->buttons) + unregister_buttons(platform->buttons); + if (platform->leds) + unregister_leds(platform->leds); + remove_proc_entry("model", diag); + remove_proc_entry("gpiomask", diag); + remove_proc_entry("diag", NULL); +} + +static struct prochandler_t proc_model = { .type = PROC_MODEL }; +static struct prochandler_t proc_gpiomask = { .type = PROC_GPIOMASK }; + +static int __init diag_init(void) +{ + static struct proc_dir_entry *p; + + platform = platform_detect(); + if (!platform) { + printk(MODULE_NAME ": Router model not detected.\n"); + return -ENODEV; + } + printk(MODULE_NAME ": Detected '%s'\n", platform->name); + + if (!(diag = proc_mkdir("diag", NULL))) { + printk(MODULE_NAME ": proc_mkdir on /proc/diag failed\n"); + return -EINVAL; + } + if ((p = create_proc_entry("model", S_IRUSR, diag))) { + p->data = (void *) &proc_model; + p->proc_fops = &diag_proc_fops; + } + if ((p = create_proc_entry("gpiomask", S_IRUSR | S_IWUSR, diag))) { + p->data = (void *) &proc_gpiomask; + p->proc_fops = &diag_proc_fops; + } + + if (platform->buttons) + register_buttons(platform->buttons); + + if (platform->leds) + register_leds(platform->leds); + + return 0; +} + +EXPORT_NO_SYMBOLS; + +module_init(diag_init); +module_exit(diag_exit); + +MODULE_AUTHOR("Mike Baker, Felix Fietkau / OpenWrt.org"); +MODULE_LICENSE("GPL"); + + +/* TODO: export existing sb_irq instead */ +static int sb_irq(void *sbh) +{ + uint idx; + void *regs; + sbconfig_t *sb; + uint32 flag, sbipsflag; + uint irq = 0; + + regs = sb_coreregs(sbh); + sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF); + flag = (R_REG(&sb->sbtpsflag) & SBTPS_NUM0_MASK); + + idx = sb_coreidx(sbh); + + if ((regs = sb_setcore(sbh, SB_MIPS, 0)) || + (regs = sb_setcore(sbh, SB_MIPS33, 0))) { + sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF); + + /* sbipsflag specifies which core is routed to interrupts 1 to 4 */ + sbipsflag = R_REG(&sb->sbipsflag); + for (irq = 1; irq <= 4; irq++, sbipsflag >>= 8) { + if ((sbipsflag & 0x3f) == flag) + break; + } + if (irq == 5) + irq = 0; + } + + sb_setcoreidx(sbh, idx); + + return irq; +} diff --git a/openwrt/target/linux/package/diag/src/diag_led.c b/openwrt/target/linux/package/diag/src/diag_led.c deleted file mode 100644 index a5a1b246de..0000000000 --- a/openwrt/target/linux/package/diag/src/diag_led.c +++ /dev/null @@ -1,340 +0,0 @@ -/* - * diag_led.c - replacement diag module - * - * Copyright (C) 2004-2006 Mike Baker, - * Imre Kaloz , - * Felix Fietkau - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Id: 005-diag_led.patch 4594 2006-08-18 13:10:19Z florian $ - */ - -/* - * ChangeLog: - * 2004/03/28 initial release - * 2004/08/26 asus & buffalo support added - * 2005/03/14 asus wl-500g deluxe and buffalo v2 support added - * 2005/04/13 added licensing informations - * 2005/04/18 base reset polarity off initial readings - * 2006/08/18 asus power led support added - * 2006/10/16 asus wl-500g premium support added - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -extern char * nvram_get(const char *name); -static void *sbh; - -// v2.x - - - - - -#define BITS(n) ((1 << n) - 1) -#define ISSET(n,b) ((n & (1 << b)) ? 1 : 0) -#define DIAG_GPIO (1<<1) -#define AOSS_GPIO (1<<6) -#define DMZ_GPIO (1<<7) -#define SES_GPIO ((1 << 2) | (1 << 3) | (1 << 5)) - -static void set_gpio(uint32 mask, uint32 value) { - sb_gpiocontrol(sbh,mask,0); - sb_gpioouten(sbh,mask,mask); - sb_gpioout(sbh,mask,value); -} - -static void v2_set_diag(u8 state) { - set_gpio(DIAG_GPIO,state); -} -static void v2_set_dmz(u8 state) { - set_gpio(DMZ_GPIO,state); -} -static void v2_set_aoss(u8 state) { - set_gpio(AOSS_GPIO,state); -} -static void v2_set_ses(u8 state) { - set_gpio(SES_GPIO, (ISSET(state, 0) << 2) | (ISSET(state, 1) << 3) | (ISSET(state, 2) << 5)); -} -// asus wl-500g (+deluxe) -#define WL500G_PWR_GPIO (1<<0) -// asus wl-500g premium -#define WL500GP_PWR_GPIO (1<<1) - -static void wl500g_set_pwr(u8 state) { - set_gpio(WL500G_PWR_GPIO,state); -} - -static void wl500gp_set_pwr(u8 state) { - set_gpio(WL500GP_PWR_GPIO,state); -} - -// v1.x - - - - - -#define LED_DIAG 0x13 -#define LED_DMZ 0x12 - -static void v1_set_diag(u8 state) { - if (!state) { - *(volatile u8*)(KSEG1ADDR(BCM4710_EUART)+LED_DIAG)=0xFF; - } else { - *(volatile u8*)(KSEG1ADDR(BCM4710_EUART)+LED_DIAG); - } -} -static void v1_set_dmz(u8 state) { - if (!state) { - *(volatile u8*)(KSEG1ADDR(BCM4710_EUART)+LED_DMZ)=0xFF; - } else { - *(volatile u8*)(KSEG1ADDR(BCM4710_EUART)+LED_DMZ); - } -} - -// - - - - - -static void ignore(u8 ignored) {}; - -// - - - - - -#define BIT_DMZ (1 << 0) -#define BIT_DIAG (1 << 2) -#define BIT_SES (BITS(3) << 3) -#define BIT_PWR (1 << 1) - -void (*set_diag)(u8 state); -void (*set_dmz)(u8 state); -void (*set_ses)(u8 state); -void (*set_pwr)(u8 state); - -static unsigned int diag_reverse = 1; -static unsigned int ses_reverse = 1; -static unsigned int pwr_reverse = 1; -static unsigned int diag = BIT_PWR; // default: diag off, pwr on, dmz off - -static void diag_change() -{ - set_diag(diag_reverse ? 0xFF : 0x00); // off - set_dmz(diag_reverse ? 0xFF : 0x00); // off - set_ses(ses_reverse ? 0xFF : 0x00); // off - set_pwr(pwr_reverse ? 0xFF : 0x00); //off - - if(diag & BIT_DIAG) - set_diag(diag_reverse ? 0x00 : 0xFF); // on - if(diag & BIT_DMZ) - set_dmz(diag_reverse ? 0x00 : 0xFF); // on - if(diag & BIT_SES) - set_ses(((ses_reverse ? ~diag : diag) >> 3) & BITS(3)); - if (diag & BIT_PWR) - set_pwr(pwr_reverse ? 0x00 : 0xFF); // on -} - -static int proc_diag(ctl_table *table, int write, struct file *filp, - void *buffer, size_t *lenp) -{ - int r; - r = proc_dointvec(table, write, filp, buffer, lenp); - if (write && !r) { - diag_change(); - } - return r; -} - -// - - - - - -static unsigned char reset_gpio = 0; -static unsigned char reset_polarity = 0; -static unsigned int reset = 0; -static unsigned char button_gpio = 0; -static unsigned char button_polarity = 0; -static unsigned int button = 0; - - -static int read_gpio(int gpio, int polarity) -{ - int res; - - if (gpio) { - sb_gpiocontrol(sbh,gpio,gpio); - sb_gpioouten(sbh,gpio,0); - res=!(sb_gpioin(sbh)&gpio); - - return (polarity ? !res : res); - } - - return 0; -} - -static int proc_reset(ctl_table *table, int write, struct file *filp, - void *buffer, size_t *lenp) -{ - reset = read_gpio(reset_gpio, reset_polarity); - - return proc_dointvec(table, write, filp, buffer, lenp); -} - -static int proc_button(ctl_table *table, int write, struct file *filp, - void *buffer, size_t *lenp) -{ - button = read_gpio(button_gpio, button_polarity); - - return proc_dointvec(table, write, filp, buffer, lenp); -} - -// - - - - - -static struct ctl_table_header *diag_sysctl_header; - -static ctl_table sys_diag[] = { - { - ctl_name: 2000, - procname: "diag", - data: &diag, - maxlen: sizeof(diag), - mode: 0644, - proc_handler: proc_diag - }, - { - ctl_name: 2001, - procname: "reset", - data: &reset, - maxlen: sizeof(reset), - mode: 0444, - proc_handler: proc_reset - }, - { - ctl_name: 2002, - procname: "button", - data: &button, - maxlen: sizeof(button), - mode: 0444, - proc_handler: proc_button - }, - { 0 } -}; - -static int __init diag_init() -{ - char *buf; - u32 board_type; - sbh = sb_kattach(); - sb_gpiosetcore(sbh); - - board_type = sb_boardtype(sbh); - printk(KERN_INFO "diag boardtype: %08x\n",board_type); - - set_diag=ignore; - set_dmz=ignore; - set_ses=ignore; - set_pwr=ignore; - - buf=nvram_get("pmon_ver") ?: ""; - if (((board_type & 0xf00) == 0x400) && (strncmp(buf, "CFE", 3) != 0)) { - buf=nvram_get("boardtype")?:""; - if (!strcmp(buf,"bcm94710dev")) { - buf=nvram_get("boardnum")?:""; - if (!strcmp(buf,"42")) { - // wrt54g v1.x - set_diag=v1_set_diag; - set_dmz=v1_set_dmz; - reset_gpio=(1<<6); - } - if (!strcmp(buf,"asusX")) { - //asus wl-500g - set_pwr=wl500g_set_pwr; - reset_gpio=(1<<6); - } - } - if (!strcmp(buf,"bcm94710ap")) { - buf=nvram_get("boardnum")?:""; - if (!strcmp(buf,"42")) { - // buffalo - set_dmz=v2_set_dmz; - reset_gpio=(1<<4); - } - if (!strcmp(buf,"44")) { - //dell truemobile - set_dmz=v2_set_dmz; - reset_gpio=(1<<0); - } - } - } else { - buf=nvram_get("boardnum")?:""; - if (!strcmp(buf,"42")) { - //linksys - set_diag=v2_set_diag; - set_dmz=v2_set_dmz; - set_ses=v2_set_ses; - - reset_gpio=(1<<6); - button_gpio=(1<<4); - - if (!strcmp((nvram_get("boardtype")?:""), "0x0101")) // WRT54G3G - ses_reverse = 0; - else - ses_reverse = 1; - } - if (!strcmp(buf,"44")) { - //motorola - reset_gpio=(1<<5); - } - if (!strcmp(buf,"00")) { - //buffalo - diag_reverse = 0; - set_dmz=v2_set_diag; - set_diag=v2_set_aoss; - reset_gpio=(1<<7); - } - if (!strcmp(buf,"45")) { /* ASUS */ - buf=nvram_get("boardtype")?:""; - if (!strcmp(buf,"0x042f")) { - //wl-500g premium - button_gpio=(1<<4); - reset_gpio=(1<<0); - set_pwr=wl500gp_set_pwr; - } else { - //wl-500g deluxe - set_pwr=wl500g_set_pwr; - reset_gpio=(1<<6); - } - } - } - - sb_gpiocontrol(sbh,reset_gpio,reset_gpio); - sb_gpioouten(sbh,reset_gpio,0); - reset_polarity=!(sb_gpioin(sbh)&reset_gpio); - - if (button_gpio) { - sb_gpiocontrol(sbh,button_gpio,button_gpio); - sb_gpioouten(sbh,button_gpio,0); - button_polarity=!(sb_gpioin(sbh)&button_gpio); - } else { - // don't create /proc/button - sys_diag[2].ctl_name = 0; - } - - diag_sysctl_header = register_sysctl_table(sys_diag, 0); - diag_change(); - - return 0; -} - -static void __exit diag_exit() -{ - unregister_sysctl_table(diag_sysctl_header); -} - -EXPORT_NO_SYMBOLS; -MODULE_AUTHOR("openwrt.org"); -MODULE_LICENSE("GPL"); - -module_init(diag_init); -module_exit(diag_exit); -- 2.30.2